home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
language
/
ici
/
ici.cpi
/
skt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-27
|
27KB
|
1,175 lines
/*
* skt.c - ICI sockets interface
*
* This is a set of extra intrinsic functions to provide ICI programs
* with access to the BSD sockets interface to the IP protocol (there is
* currently no support for other protocol families but it is easily
* provided.)
*
* The ICI interface does not follow the BSD C interface but adopts
* practices suitable for the ICI environment.
*/
#include "fwd.h"
#ifndef NOSKT
#include <string.h>
#include <sys/param.h>
#undef isset /* sys/param.h defines set macros that conflict with ICI's */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <pwd.h>
#if __hpux
#include <unistd.h>
#endif
#include "buf.h"
#include "exec.h"
#include "op.h"
#include "fwd.h"
#include "func.h"
#include "int.h"
#include "set.h"
#include "struct.h"
#include "str.h"
#include "skt.h"
string_t *string_read;
string_t *string_write;
string_t *string_except;
string_t *string_msg;
string_t *string_addr;
#if defined(sun) && __STDC__
int close(int);
int socket(int, int, int);
int listen(int, int);
int accept(int, struct sockaddr *, int *);
int connect(int, struct sockaddr *, int);
int bind(int, struct sockaddr *, int);
int getdtablesize(void);
int sendto(int, char *, int, int, struct sockaddr *, int);
int send(int, char *, int, int);
int recvfrom(int, char *, int, int, struct sockaddr *, int *);
int recv(int, char *, int, int);
int getsockopt(int, int, int, char *, int *);
int setsockopt(int, int, int, char *, int);
int getdomainname(char *, int);
int gethostname(char *, int);
int getuid(void);
int getpeername(int, struct sockaddr *, int *);
int getsockname(int, struct sockaddr *, int *);
#endif
/*
* Definitions to make a new type, socket, for representing network connections
*/
STATIC long
mark_socket(o)
object_t *o;
{
o->o_flags |= O_MARK;
return sizeof (skt_t);
}
STATIC long
hash_socket(s)
skt_t *s;
{
return (long)s->s_skt * 7;
}
STATIC int
cmp_socket(s1, s2)
skt_t *s1;
skt_t *s2;
{
return s1->s_skt != s2->s_skt;
}
type_t socket_type =
{
mark_socket,
free_simple,
hash_socket,
cmp_socket,
copy_simple,
assign_simple,
fetch_simple,
"socket"
};
skt_t *
new_socket(fd)
int fd;
{
skt_t *s;
if ((s = talloc(skt_t)) != NULL)
{
objof(s)->o_type = &socket_type;
objof(s)->o_tcode = TC_OTHER;
objof(s)->o_flags = 0;
objof(s)->o_nrefs = 1;
s->s_skt = fd;
rego(s);
}
return sktof(atom(objof(s), 1));
}
static int need_strings = 1;
static int
define_strings()
{
if ((string_read = new_cname("read")) == NULL)
return 1;
if ((string_write = new_cname("write")) == NULL)
return 1;
if ((string_except = new_cname("except")) == NULL)
return 1;
if ((string_msg = new_cname("msg")) == NULL)
return 1;
if ((string_addr = new_cname("addr")) == NULL)
return 1;
return need_strings = 0;
}
/*
* Parse an IP address in the format "service[@host]" where service is a
* port number of service name (in the form "name[/proto]" where name is
* the name of the service and, the optional, proto is either "tcp" or
* "udp"). The host part is optional and if not specified defaults to
* the defhost parameter. The host may be specified as an IP address
* in dotted decimal notation or as a hostname. Three special values
* are recognsied, "." stands for the local host, "?" stands for any
* host and "*" means broadcast. The address may be NULL to just
* initialise the socket address to defhost port 0.
*
* The sockaddr structure is filled in and 0 returned if all is okay.
* When a error occurs the error string is set and 1 is returned.
*/
static struct sockaddr_in *
parseaddr(raddr, defhost, saddr)
char *raddr;
long defhost;
struct sockaddr_in *saddr;
{
char addr[1024];
char *host;
short port;
saddr->sin_family = PF_INET;
saddr->sin_addr.s_addr = defhost;
saddr->sin_port = 0;
if (raddr == NULL)
return saddr;
strcpy(addr, raddr);
if ((host = strchr(addr, '@')) != NULL)
{
struct hostent *hostent;
long hostaddr;
*host++ = 0;
if (!strcmp(host, "."))
hostaddr = INADDR_LOOPBACK;
else if (!strcmp(host, "?"))
hostaddr = INADDR_ANY;
else if (!strcmp(host, "*"))
hostaddr = INADDR_BROADCAST;
else if ((hostent = gethostbyname(host)) != NULL)
memcpy(&hostaddr, hostent->h_addr, sizeof hostaddr);
else
{
error = "unknown host";
return NULL;
}
saddr->sin_addr.s_addr = hostaddr;
}
if (sscanf(addr, "%hu", &port) != 1)
{
char *proto;
struct servent *servent;
if ((proto = strchr(addr, '/')) != NULL)
*proto++ = 0;
if ((servent = getservbyname(addr, proto)) == NULL)
{
error = "unknown service";
return NULL;
}
port = ntohs(servent->s_port);
}
saddr->sin_port = htons(port);
return saddr;
}
/*
* Turn a port number and IP address into a nice looking string ;-)
*/
static char *
unparse_addr(addr)
struct sockaddr_in *addr;
{
static char buf[256];
struct servent *serv;
struct hostent *host;
if ((serv = getservbyport(addr->sin_port, NULL)) != NULL)
strcpy(buf, serv->s_name);
else
sprintf(buf, "%d", addr->sin_port);
strcat(buf, "@");
if ((host = gethostbyaddr((char *)addr->sin_addr.s_addr, sizeof addr->sin_addr, AF_INET)) == NULL)
strcat(buf, inet_ntoa(addr->sin_addr));
else
strcat(buf, host->h_name);
return buf;
}
/*
* Error return utility. Formats the exception string with the
* the message followed by the system error message and returns
* 1 for use in error returns.
*/
static int
serr(msg)
char *msg;
{
sprintf(buf, "%s: %s", msg, syserr());
error = buf;
return 1;
}
/*
* Create a socket with a certain protocol (currently TCP or UDP)
* and return its descriptor. Raises exception if the protocol
* is unknown or the socket cannot be created.
*
* ICI usage,
*
* skt = socket(proto);
*
* Where proto is a string ("tcp" or "udp") and the result is the socket.
*/
STATIC int
f_socket()
{
skt_t *skt;
char *proto;
int type;
int fd;
if (typecheck("s", &proto))
return 1;
if (!strcmp(proto, "tcp"))
type = SOCK_STREAM;
else if (!strcmp(proto, "udp"))
type = SOCK_DGRAM;
else
{
error = "unsupported protocol";
return 1;
}
if ((fd = socket(PF_INET, type, 0)) == -1)
return serr("socket");
if ((skt = new_socket(fd)) == NULL)
{
close(fd);
return 1;
}
return loose_ret(objof(skt));
}
/*
* Tell the system to listen for connections on a socket. Raises
* the appropriate system exception if it fails.
*
* ICI usage,
*
* skt = listen(skt);
*
* Where skt is the socket descriptor as returned by socket(). The
* result of listen is its parameter (to allow "functional" programming.)
*
*/
STATIC int
f_listen()
{
skt_t *skt;
if (typecheck("o", &skt))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
if (listen(skt->s_skt, 5) == -1)
return serr("listen");
return loose_ret(objof(skt));
}
/*
* Accept a connection on a socket. Returns the descriptor for the
* new socket connection or raises an exception.
*
* ICI usage,
*
* new_skt = accept(skt);
*
* Where skt is a socket descriptor of a TCP socket that has been
* marked to accept connections (i.e., been passed to listen()).
* The result is the socket descriptor of the new connection.
*/
STATIC int
f_accept()
{
skt_t *skt;
skt_t *new;
int fd;
if (typecheck("o", &skt))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
if ((fd = accept(skt->s_skt, NULL, NULL)) == -1)
return serr("accept");
if ((new = new_socket(fd)) != NULL)
got(new);
return obj_ret(objof(new));
}
/*
* Connect a socket to an address. Raises an exception if it fails
* for some reason or returns the socket passed as the first
* parameter which is now connected to the address specified as
* the second parameter.
*
* ICI usage,
*
* skt = connect(skt, address);
*
* Skt is a socket desciptor and address is a network address as
* accepted by parseaddr().
*
*/
STATIC int
f_connect()
{
skt_t *skt;
char *addr;
struct sockaddr_in sockaddr;
if (typecheck("os", &skt, &addr))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
if (parseaddr(addr, INADDR_LOOPBACK, &sockaddr) == NULL)
return 1;
if (connect(skt->s_skt, (struct sockaddr *)&sockaddr, sizeof sockaddr) == -1)
return serr("connect");
return loose_ret(objof(skt));
}
/*
* Bind an address to a socket. Returns socket descriptor or raises
* an exception. Default host address is INADDR_ANY which is mostly
* used with TCP sockets for servers (i.e. a server can use the
* code "bind(socket("tcp"), port)" to create their sockets.)
*/
STATIC int
f_bind()
{
skt_t *skt;
char *addr;
struct sockaddr_in sockaddr;
if (typecheck("os", &skt, &addr))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
if (parseaddr(addr, INADDR_ANY, &sockaddr) == NULL)
return 1;
if (bind(skt->s_skt, (struct sockaddr *)&sockaddr, sizeof sockaddr) == -1)
return serr("bind");
return loose_ret(objof(skt));
}
#if __hpux
/*
* Fake getdtablesize(2) call for HPUS.
*/
static int
getdtablesize()
{
return (int)sysconf(_SC_OPEN_MAX);
}
#endif
/*
* Check for ready sockets with optional timeout. This returns a
* structure of three sets of descriptors. The parameters to
* this function are complex. It takes two types of parameters,
* an integer timeout value (in milliseconds) or up to to three
* sets of socket descriptors (at least one set must be passed.)
* The first set is taken to be the sockets to check for reading,
* the second set is checked for writing and the third set is
* checked for "urgent" status. The write and urgent sets are
* optional. Any set may be specified as NULL. This is used to
* specify, say, just a write set when there is no read set.
* The read set must be specified (becauses the others are
* optional) but there are no members.
*/
STATIC int
f_select()
{
int i;
int n;
int dtabsize;
long timeout = -1;
struct fd_set fds[3];
struct fd_set *rfds = NULL, *wfds = NULL, *efds = NULL;
struct timeval timeval, *tv;
struct_t *result;
set_t *set;
if (need_strings && define_strings())
return 1;
if (NARGS() == 0)
{
error = "incorrect number of arguments for select()";
return 1;
}
for (i = 0; i < NARGS(); ++i)
{
if (isint(ARG(i)))
{
if (timeout != -1)
{
error = "more than one timeout parameter";
return 1;
}
timeout = intof(ARG(i))->i_value;
if (timeout < 0)
{
error = "bad timeout";
return 1;
}
}
else if (isset(ARG(i)) || isnull(ARG(i)))
{
int whichset = -1; /* Can be 0, 1 or 2 */
int j;
slot_t *sl;
if (++whichset > 2)
{
error = "too many set parameters to select()";
return 1;
}
if (isnull(ARG(i)))
{
switch (whichset)
{
case 0:
rfds = NULL;
break;
case 1:
wfds = NULL;
break;
case 2:
efds = NULL;
break;
}
}
else
{
struct fd_set *fs = 0;
switch (whichset)
{
case 0:
fs = rfds = &fds[0];
break;
case 1:
fs = wfds = &fds[1];
break;
case 2:
fs = efds = &fds[2];
break;
}
FD_ZERO(fs);
set = setof(ARG(i));
for (j = 0; j < set->s_nslots; ++j)
{
int k;
if ((sl = (slot_t *)&set->s_slots[j])->sl_key == NULL)
continue;
if (!isskt(sl->sl_key))
continue;
k = sktof(sl->sl_key)->s_skt;
FD_SET(k, fs);
}
}
}
else
{
sprintf(buf, "select() passed a %s", ARG(i)->o_type->t_name);
error = buf;
return 1;
}
}
if (rfds == NULL && wfds == NULL && efds == NULL)
{
error = "no set parameters to select";
return 1;
}
if (timeout == -1)
tv = NULL;
else
{
tv = &timeval;
tv->tv_sec = timeout / 1000;
tv->tv_usec = (timeout % 1000) * 1000;
}
dtabsize = getdtablesize();
if ((n = select(dtabsize, rfds, wfds, efds, tv)) < 0)
{
error = syserr();
return 1;
}
if (n == 0)
{
error = "timeout";
return 1;
}
if ((result = new_struct()) == NULL)
return 1;
if ((set = new_set()) == NULL)
goto fail;
for (i = 0; n > 0 && i < dtabsize; ++i)
{
if (FD_ISSET(i, rfds))
{
skt_t *ii = new_socket(i);
if (ii == NULL)
{
loose(objof(set));
goto fail;
}
loose(objof(ii));
if (assign(set, ii, objof(o_one)))
{
loose(objof(set));
goto fail;
}
--n;
}
}
loose(objof(set));
if (assign(result, string_read, set))
goto fail;
if ((set = new_set()) == NULL)
goto fail;
for (i = 0; n > 0 && i < dtabsize; ++i)
{
if (FD_ISSET(i, wfds))
{
skt_t *ii = new_socket(i);
if (ii == NULL)
{
loose(objof(set));
goto fail;
}
loose(objof(ii));
if (assign(set, ii, objof(o_one)))
{
loose(objof(set));
goto fail;
}
--n;
}
}
loose(objof(set));
if (assign(result, string_write, set))
goto fail;
if ((set = new_set()) == NULL)
goto fail;
for (i = 0; n > 0 && i < dtabsize; ++i)
{
if (FD_ISSET(i, efds))
{
skt_t *ii = new_socket(i);
if (ii == NULL)
{
loose(objof(set));
goto fail;
}
if (assign(set, ii, objof(o_one)))
{
loose(objof(set));
goto fail;
}
--n;
}
}
loose(objof(set));
if (assign(result, string_except, set))
goto fail;
return loose_ret(objof(result));
fail:
loose(objof(result));
return 1;
}
/*
* Send a message to a specific address.
*
* Usage
*
* sendto(skt, msg, address)
*
*/
STATIC int
f_sendto()
{
char *addr, *msg;
int len, n;
skt_t *skt;
struct sockaddr_in sockaddr;
if (typecheck("oss", &skt, &msg, &addr))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
len = strlen(msg);
if (parseaddr(addr, INADDR_LOOPBACK, &sockaddr) == NULL)
return 1;
if ((n = sendto(skt->s_skt, msg, len, 0, (struct sockaddr *)&sockaddr, sizeof sockaddr)) < 0)
return serr("sendto");
if (n != len)
{
error = "short write";
return 1;
}
return loose_ret(objof(&o_null));
}
#if 0
/*
* Turn a textual send option into the correct bits
*/
static int
flagval(flag)
char *flag;
{
if (!strcmp(flag, "oob"))
return MSG_OOB;
if (!strcmp(flag, "peek"))
return MSG_PEEK;
if (!strcmp(flag, "dontroute"))
return MSG_DONTROUTE;
return -1;
}
#endif
/*
* Receive a message and get the source address. This returns a structure
* (at the ICI level) containing the data, in result.msg, and the address
* in result.addr.
*/
STATIC int
f_recvfrom()
{
skt_t *skt;
int len;
int nb;
char *msg;
struct sockaddr_in addr;
int addrsz = sizeof addr;
struct_t *result;
string_t *s;
if (need_strings && define_strings())
return 1;
if (typecheck("oi", &skt, &len))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
if ((msg = zalloc(len+1)) == NULL)
return 1;
if ((nb = recvfrom(skt->s_skt, msg, len, 0, (struct sockaddr *)&addr, &addrsz)) == -1)
{
zfree(msg);
return serr("recv");
}
if (nb == 0)
{
zfree(msg);
return loose_ret(objof(&o_null));
}
msg[nb] = 0;
if ((result = new_struct()) == NULL)
{
zfree(msg);
return 1;
}
loose(result);
if ((s = new_cname(msg)) == NULL)
{
zfree(msg);
return 1;
}
zfree(msg);
if (assign(result, string_msg, s))
return 1;
if ((s = new_cname(unparse_addr(&addr))) == NULL)
return 1;
if (assign(result, string_addr, s))
return 1;
return obj_ret(objof(result));
}
/*
* Send a message on a socket.
*/
STATIC int
f_send()
{
skt_t *skt;
int len;
char *msg;
if (typecheck("os", &skt, &msg))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
len = strlen(msg);
if (send(skt->s_skt, msg, len, 0) != len)
{
error = "short write";
return 1;
}
return loose_ret(objof(&o_null));
}
/*
* Receive a message.
*/
STATIC int
f_recv()
{
skt_t *skt;
int len;
int nb;
int rc;
char *msg;
if (typecheck("oi", &skt, &len))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
if ((msg = zalloc(len+1)) == NULL)
return 1;
if ((nb = recv(skt->s_skt, msg, len, 0)) == -1)
{
free(msg);
return serr("recv");
}
if (nb == 0)
{
zfree(msg);
return loose_ret(objof(&o_null));
}
msg[nb] = 0;
rc = str_ret(msg);
zfree(msg);
return rc;
}
/*
* Turn a textual socket option name to the actual number.
*/
static int
sockopt(opt)
char *opt;
{
long o = -1;
int i;
static struct
{
char *name;
int value;
}
opts[] =
{
{"debug", SO_DEBUG},
{"reuseaddr", SO_REUSEADDR},
{"keepalive", SO_KEEPALIVE},
{"dontroute", SO_DONTROUTE},
{"useloopback", SO_USELOOPBACK},
{"linger", SO_LINGER},
{"broadcast", SO_BROADCAST},
{"oobinline", SO_OOBINLINE},
{"sndbuf", SO_SNDBUF},
{"rcvbuf", SO_RCVBUF},
{"type", SO_TYPE},
{"error", SO_ERROR}
};
for (i = 0; o == -1 && i < sizeof opts/sizeof opts[0]; ++i)
if (!strcmp(opt, opts[i].name))
o = opts[i].value;
return o;
}
/*
* Get socket options.
*
* All option values get returned as integers. The only special processing
* is of the "linger" option. This gets returned as the lingering time if
* it is set or -1 if lingering is not enabled.
*/
STATIC int
f_getsockopt()
{
skt_t *skt;
char *opt;
int o;
char *optval;
int optlen;
struct linger linger;
int intvar;
optval = (char *)&intvar;
optlen = sizeof intvar;
if (typecheck("os", &skt, &opt))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
switch (o = sockopt(opt))
{
case SO_DEBUG:
case SO_REUSEADDR:
case SO_KEEPALIVE:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_TYPE:
case SO_OOBINLINE:
case SO_SNDBUF:
case SO_RCVBUF:
case SO_ERROR:
break;
case SO_LINGER:
optval = (char *)&linger;
optlen = sizeof linger;
break;
default:
sprintf(buf, "bad socket option \"%s\"", opt);
error = buf;
return 1;
}
if (getsockopt(skt->s_skt, SOL_SOCKET, o, optval, &optlen) == -1)
return serr("getsockopt");
if (o == SO_LINGER)
intvar = linger.l_onoff ? linger.l_linger : -1;
else
{
switch (o)
{
case SO_TYPE:
case SO_SNDBUF:
case SO_RCVBUF:
case SO_ERROR:
break;
default:
intvar = !!intvar;
}
}
return int_ret(intvar);
}
/*
* Set socket options.
*
* All socket options are integers. Again linger is a special case. The
* option value is the linger time, if zero or negative lingering is
* turned off.
*/
STATIC int
f_setsockopt()
{
skt_t *skt;
char *opt;
int o;
char *optval;
int optlen;
int intvar;
struct linger linger;
optval = (char *)&intvar;
optlen = sizeof intvar;
if (typecheck("osi", &skt, &opt, &intvar))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
switch (o = sockopt(opt))
{
case SO_DEBUG:
case SO_REUSEADDR:
case SO_KEEPALIVE:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_TYPE:
case SO_OOBINLINE:
case SO_SNDBUF:
case SO_RCVBUF:
case SO_ERROR:
break;
case SO_LINGER:
linger.l_onoff = intvar > 0;
linger.l_linger = intvar;
optval = (char *)&linger;
optlen = sizeof linger;
break;
default:
sprintf(buf, "bad socket option \"%s\"", opt);
error = buf;
return 1;
}
if (setsockopt(skt->s_skt, SOL_SOCKET, o, optval, optlen) == -1)
return serr("setsockopt");
return loose_ret(objof(&o_null));
}
/*
* Get the domain name for the host.
*/
STATIC int
f_domainname()
{
static string_t *domainname = NULL;
if (domainname == NULL)
{
char buf[1024];
if (getdomainname(buf, sizeof buf) == -1)
return serr("getdomainname");
if ((domainname = new_cname(buf)) == NULL)
return 1;
got(domainname);
}
return loose_ret((object_t *)stringof(domainname));
}
/*
* Get the host name as a string.
*/
STATIC int
f_hostname()
{
static string_t *hostname = NULL;
if (hostname == NULL)
{
char buf[MAXHOSTNAMELEN];
if (gethostname(buf, sizeof buf) == -1)
return serr("gethostname");
if ((hostname = new_cname(buf)) == NULL)
return 1;
got(hostname);
}
return loose_ret((object_t *)stringof(hostname));
}
/*
* Return the name of the current user or the user with the given uid.
*/
STATIC int
f_username()
{
char *getenv();
struct passwd *pwent;
long uid = getuid();
char *s;
if (NARGS() > 0)
{
if (typecheck("i", &uid))
return 1;
}
if ((pwent = getpwuid(uid)) == NULL)
{
sprintf(buf, "can't find name for uid %ld", uid);
error = buf;
return 1;
}
s = pwent->pw_name;
return loose_ret((object_t *)new_cname(s));
}
/*
* Get the address of the connected socket's client.
*/
STATIC int
f_getpeername()
{
struct sockaddr_in addr;
int len = sizeof addr;
skt_t *skt;
if (typecheck("o", &skt))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
if (getpeername(skt->s_skt, (struct sockaddr *)&addr, &len) == -1)
return serr("getpeername");
return str_ret(unparse_addr(&addr));
}
/*
* Get a socket's address.
*/
STATIC int
f_getsockname()
{
struct sockaddr_in addr;
int len = sizeof addr;
skt_t *skt;
if (typecheck("o", &skt))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
if (getsockname(skt->s_skt, (struct sockaddr *)&addr, &len) == -1)
return serr("getsockname");
return str_ret(unparse_addr(&addr));
}
/*
* Get the port number bound to a socket.
*/
STATIC int
f_getportno()
{
struct sockaddr_in addr;
int len = sizeof addr;
skt_t *skt;
if (typecheck("o", &skt))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
if (getsockname(skt->s_skt, (struct sockaddr *)&addr, &len) == -1)
return serr("getsockname");
return int_ret(addr.sin_port);
}
/*
* Return the IP address for the specified host. The address is returned
* as a string containing the dotted decimal form of the host's address.
* If the host's address cannot be resolved an error, "no such host"
* is raised.
*/
STATIC int
f_gethostbyname()
{
char *name;
struct hostent *hostent;
struct in_addr addr;
if (typecheck("s", &name))
return 1;
if ((hostent = gethostbyname(name)) == NULL)
{
error = "no such host";
return 1;
}
memcpy(&addr, *hostent->h_addr_list, sizeof addr);
return str_ret(inet_ntoa(addr));
}
/*
* Return the name of a host given an IP address. The IP address is
* specified as either a string containing an address in dotted
* decimal or an integer (remember ICI ints are at least 32 bits.)
* The name is returned as a string. If the name cannot be resolved
* an exception, "unknown host", is raised.
*/
STATIC int
f_gethostbyaddr()
{
long intaddr;
char *straddr = NULL;
if (typecheck("s", &straddr))
{
straddr = 0;
if (typecheck("i", &intaddr))
return 1;
}
return 1;
}
/*
* f_sktno - return the OS socket descriptor (file descriptor) for a socket
*/
STATIC int
f_sktno()
{
skt_t *skt;
if (typecheck("o", &skt))
return 1;
if (!isskt(objof(skt)))
return argerror(0);
return int_ret(skt->s_skt);
}
/*
* f_sktopen - turn a socket descriptor into a file
*/
STATIC int
f_sktopen()
{
skt_t *skt;
char *mode;
FILE *stream;
file_t *f;
if (typecheck("os", &skt, &mode))
{
if (typecheck("o", &skt))
return 1;
mode = "r";
}
if (!isskt(objof(skt)))
return argerror(0);
if ((stream = fdopen(skt->s_skt, mode)) == NULL)
{
error = "can't fdopen";
return 1;
}
if ((f = new_file((char *)stream, &stdio_ftype, NULL)) == NULL)
{
fclose(stream);
return 1;
}
return obj_ret(objof(f));
}
/*
* This is the configuration table that defines our functions to
* the interpreter. The CF_OBJ macro comes from func.h and defines
* the necessary object header for out cfunc_t table. The string
* is the ICI name for the function. The last field is the address
* of the C function that implements this function.
*/
cfunc_t skt_cfuncs[] =
{
{CF_OBJ, "socket", f_socket},
{CF_OBJ, "listen", f_listen},
{CF_OBJ, "accept", f_accept},
{CF_OBJ, "connect", f_connect},
{CF_OBJ, "bind", f_bind},
{CF_OBJ, "select", f_select},
{CF_OBJ, "getsockopt", f_getsockopt},
{CF_OBJ, "setsockopt", f_setsockopt},
{CF_OBJ, "domainname", f_domainname},
{CF_OBJ, "hostname", f_hostname},
{CF_OBJ, "username", f_username},
{CF_OBJ, "getpeername", f_getpeername},
{CF_OBJ, "getsockname", f_getsockname},
{CF_OBJ, "sendto", f_sendto},
{CF_OBJ, "recvfrom", f_recvfrom},
{CF_OBJ, "send", f_send},
{CF_OBJ, "recv", f_recv},
{CF_OBJ, "getportno", f_getportno},
{CF_OBJ, "gethostbyname", f_gethostbyname},
{CF_OBJ, "gethostbyaddr", f_gethostbyaddr},
{CF_OBJ, "sktno", f_sktno},
{CF_OBJ, "sktopen", f_sktopen},
{CF_OBJ}
};
#endif /*NOSKT*/